﻿using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;
using System.Xml;
using ControleEstoque.Data;
using System.Data.SqlTypes;
using System.IO;
using System.Text;

namespace ControleEstoque.Data
{
	public class EstoqueLocalizacao
	{
		public const string Insert = @"INSERT INTO [ControleAtivo].[dbo].[EstoqueLocalizacao]
           ([EstoqueLocalizacaoRFID]
           ,[AtivoId]
           ,[LocalArmazenagemId]
           ,[EstoqueLocalizacaoRFIDPai]
           ,[EstoqueLocalizacaoTamanhoCaixa]
           ,[EstoqueLocalizacaoDataValidade]
		   ,[EstoqueLocalizacaoQuantidade]
			,[EstoqueLocalizacaoHierarquia]
			,[EstoqueLocalizacaoLote])
     VALUES
           (@estoqueLocalizacaoRFID
           ,@ativoId
           ,@localArmazenagemId
           ,@estoqueLocalizacaoRFIDPai
           ,@estoqueLocalizacaoTamanhoCaixa
           ,@estoqueLocalizacaoDataValidade
		   ,@estoqueLocalizacaoQuantidade
			,@estoqueLocalizacaoHierarquia
			,@estoqueLocalizacaoLote)";

		public const string Update = @"UPDATE [ControleAtivo].[dbo].[EstoqueLocalizacao]
   SET [AtivoId] = @ativoId
      ,[LocalArmazenagemId] = @localArmazenagemId
      ,[EstoqueLocalizacaoRFIDPai] = @estoqueLocalizacaoRFIDPai
      ,[EstoqueLocalizacaoHierarquia] = @estoqueLocalizacaoHierarquia
      ,[EstoqueLocalizacaoTamanhoCaixa] = @estoqueLocalizacaoTamanhoCaixa
      ,[EstoqueLocalizacaoDataValidade] = @estoqueLocalizacaoDataValidade
      ,[EStoqueLocalizacaoQuantidade] = @estoqueLocalizacaoQuantidade,
		,[EstoqueLocalizacaoLote] = @estoqueLocalizacaoLote
 WHERE [EstoqueLocalizacaoRFID] = @estoqueLocalizacaoRFID";

		public const string Delete = @"DELETE FROM [ControleAtivo].[dbo].[EstoqueLocalizacao]
      WHERE [EstoqueLocalizacaoRFID] = @estoqueLocalizacaoRFID";

		public static void GerarEstoqueLocalizacaoHierarquia2(SqlConnection connection, DataRow inserted)
		{
			if (!inserted["estoqueLocalizacaoRFIDPai"].Equals(inserted["estoqueLocalizacaoRFID"]))
			{
				using (SqlCommand command = new SqlCommand(@"
SELECT EstoqueLocalizacaoHierarquia
FROM EstoqueLocalizacao
WHERE EstoqueLocalizacaoRFID = @estoqueLocalizacaoRFIDPai", connection))
				{
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoRFIDPai", inserted["estoqueLocalizacaoRFIDPai"]));
					inserted["EstoqueLocalizacaoHierarquia"] = command.ExecuteScalar() as string;

				}
			}
			else
			{
				inserted["EstoqueLocalizacaoHierarquia"] = string.Empty;
			}
			inserted["EstoqueLocalizacaoHierarquia"] = (inserted["EstoqueLocalizacaoHierarquia"] as string) + ((Guid)inserted["EstoqueLocalizacaoRFID"]).ToString("N") + "#";
		}

		[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read, SystemDataAccess = SystemDataAccessKind.Read)]
		public static SqlXml ConsultaEstoque(SqlInt32 ativoId, SqlInt32 localArmazenagemId, string estoqueLocalizacaoRFID, SqlDateTime movimentacaoDataInicial, SqlDateTime movimentacaoDataFinal)
		{
			using (SqlConnection connection = new SqlConnection(@"context connection=true"))
			{
				connection.Open();
				XmlDocument xDoc = new XmlDocument();
				System.Collections.Generic.Dictionary<Guid, XmlElement> elements = new System.Collections.Generic.Dictionary<Guid, XmlElement>();

				XmlElement rootElement = xDoc.CreateElement("EstoqueLocalizacaoRoot");
				xDoc.AppendChild(rootElement);

				using (SqlCommand command = new SqlCommand())
				{
					command.Connection = connection;
					string commandOriginal = @"SELECT EstoqueLocalizacao.*, Ativo.AtivoNome, LocalArmazenagem.LocalArmazenagemNome
FROM EstoqueLocalizacao
	INNER JOIN LocalArmazenagem ON EstoqueLocalizacao.LocalArmazenagemId = LocalArmazenagem.LocalArmazenagemId
	LEFT JOIN Ativo ON EstoqueLocalizacao.AtivoId = Ativo.AtivoId
WHERE EstoqueLocalizacaoRFID LIKE @estoqueLocalizacaoRFID";
					command.CommandText = commandOriginal;
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoRFID", string.IsNullOrEmpty(estoqueLocalizacaoRFID) ? "%" : estoqueLocalizacaoRFID));

					if (!ativoId.IsNull)
					{
						command.CommandText += " AND EstoqueLocalizacao.AtivoId = @ativoId";
						command.Parameters.Add(new SqlParameter("ativoId", ativoId));
					}
					if (!localArmazenagemId.IsNull)
					{
						command.CommandText += " AND EstoqueLocalizacao.LocalArmazenagemId = @localArmazenagemId";
						command.Parameters.Add(new SqlParameter("localArmazenagemId", localArmazenagemId));
					}

					SqlDataAdapter adapter = new SqlDataAdapter(command);

					DataTable estoqueLocalizacao = new DataTable();

					adapter.Fill(estoqueLocalizacao);

					command.CommandText = commandOriginal;

					foreach (DataRow row in estoqueLocalizacao.Rows)
					{
						Guid gEstoqueLocalizacaoRFID = (Guid)(row["EstoqueLocalizacaoRFID"]);

						if (!elements.ContainsKey(gEstoqueLocalizacaoRFID))
						{

							XmlElement xEstoqueLocalizacao = xDoc.CreateElement("EstoqueLocalizacao");

							foreach (DataColumn column in estoqueLocalizacao.Columns)
							{
								XmlAttribute xColumn = xDoc.CreateAttribute(column.ColumnName);
								xColumn.Value = row[column].ToString();
								xEstoqueLocalizacao.Attributes.Append(xColumn);
							}

							elements.Add(gEstoqueLocalizacaoRFID, xEstoqueLocalizacao);

							while (xEstoqueLocalizacao.GetAttribute("EstoqueLocalizacaoRFIDPai") != xEstoqueLocalizacao.GetAttribute("EstoqueLocalizacaoRFID") && xEstoqueLocalizacao.ParentNode == null)
							{
								Guid estoqueLocalizacaoRFIDPai = new Guid(xEstoqueLocalizacao.GetAttribute("EstoqueLocalizacaoRFIDPai"));
								if (elements.ContainsKey(estoqueLocalizacaoRFIDPai))
								{
									if (elements[estoqueLocalizacaoRFIDPai].SelectSingleNode("EstoqueLocalizacaoFilhos") == null)
									{
										XmlElement xEstoqueLocalizacaoFilhos = xDoc.CreateElement("EstoqueLocalizacaoFilhos");
										elements[estoqueLocalizacaoRFIDPai].AppendChild(xEstoqueLocalizacaoFilhos);
									}
									elements[estoqueLocalizacaoRFIDPai].SelectSingleNode("EstoqueLocalizacaoFilhos").AppendChild(xEstoqueLocalizacao);
									xEstoqueLocalizacao = elements[estoqueLocalizacaoRFIDPai];
								}
								else
								{
									command.Parameters["estoqueLocalizacaoRFID"].Value = estoqueLocalizacaoRFIDPai;

									DataTable estoqueLocalizacaoPai = new DataTable();

									adapter.Fill(estoqueLocalizacaoPai);

									foreach (DataRow pai in estoqueLocalizacaoPai.Rows)
									{
										XmlElement xEstoqueLocalizacaoPai = xDoc.CreateElement("EstoqueLocalizacao");

										foreach (DataColumn column in estoqueLocalizacaoPai.Columns)
										{
											XmlAttribute xColumn = xDoc.CreateAttribute(column.ColumnName);
											xColumn.Value = pai[column].ToString();
											xEstoqueLocalizacaoPai.Attributes.Append(xColumn);
										}

										XmlElement xEstoqueLocalizacaoFilhos = xDoc.CreateElement("EstoqueLocalizacaoFilhos");
										xEstoqueLocalizacaoPai.AppendChild(xEstoqueLocalizacaoFilhos);

										xEstoqueLocalizacaoFilhos.AppendChild(xEstoqueLocalizacao);
										xEstoqueLocalizacao = xEstoqueLocalizacaoPai;

										elements.Add(estoqueLocalizacaoRFIDPai, xEstoqueLocalizacao);
									}
								}
							}

							if (xEstoqueLocalizacao.GetAttribute("EstoqueLocalizacaoRFIDPai") == xEstoqueLocalizacao.GetAttribute("EstoqueLocalizacaoRFID") && xEstoqueLocalizacao.ParentNode == null)
							{
								rootElement.AppendChild(xEstoqueLocalizacao);
							}
						}
					}
				}


				if (!movimentacaoDataInicial.IsNull || !movimentacaoDataFinal.IsNull)
				{
					using (SqlDataAdapter adapter = new SqlDataAdapter(new SqlCommand("SELECT Movimentacao.*, LocalArmazenagemNome FROM Movimentacao INNER JOIN LocalArmazenagem ON Movimentacao.LocalArmazenagemId = LocalArmazenagem.LocalArmazenagemId WHERE MovimentacaoData BETWEEN @movimentacaoDataInicial AND @movimentacaoDataFinal AND EstoqueLocalizacaoRFID = @estoqueLocalizacaoRFID ORDER BY MovimentacaoData", connection)))
					{
						adapter.SelectCommand.Parameters.Add(new SqlParameter("movimentacaoDataInicial", (movimentacaoDataInicial.IsNull ? new DateTime(1900, 1, 1) : movimentacaoDataInicial.Value)));
						adapter.SelectCommand.Parameters.Add(new SqlParameter("movimentacaoDataFinal", (movimentacaoDataFinal.IsNull ? new DateTime(2099, 12, 31) : movimentacaoDataFinal.Value)));
						adapter.SelectCommand.Parameters.Add(new SqlParameter("estoqueLocalizacaoRFID", SqlDbType.UniqueIdentifier));
						GetMovimentacoes(adapter, xDoc, rootElement.FirstChild as XmlElement);
					}
				}

				StringBuilder sb = new StringBuilder();
				XmlWriter xWriter = XmlWriter.Create(sb);
				xDoc.WriteTo(xWriter);
				xWriter.Close();

				XmlReader xReader = XmlReader.Create(new StringReader(sb.ToString()));

				SqlXml toReturn = new SqlXml(xReader);

				xReader.Close();
				connection.Close();

				return toReturn;
			}
		}

		private static void GetMovimentacoes(SqlDataAdapter adapter, XmlDocument xDoc, XmlElement xEstoqueLocalizacao)
		{
			Guid estoqueLocalizacaoRFID = new Guid(xEstoqueLocalizacao.GetAttribute("EstoqueLocalizacaoRFID"));

			adapter.SelectCommand.Parameters["estoqueLocalizacaoRFID"].Value = estoqueLocalizacaoRFID;

			DataTable movimentacao = new DataTable();

			adapter.Fill(movimentacao);

			if (movimentacao.Rows.Count > 0)
			{
				XmlElement xMovimentacoes = xDoc.CreateElement("Movimentacoes");
				xEstoqueLocalizacao.AppendChild(xMovimentacoes);

				foreach (DataRow row in movimentacao.Rows)
				{
					XmlElement xMovimentacao = xDoc.CreateElement("Movimentacao");

					foreach (DataColumn column in movimentacao.Columns)
					{
						XmlAttribute xColumn = xDoc.CreateAttribute(column.ColumnName);
						xColumn.Value = row[column].ToString();
						xMovimentacao.Attributes.Append(xColumn);
					}

					xMovimentacoes.AppendChild(xMovimentacao);
				}


				XmlNode xEstoqueLocalizacaoFilhos = xEstoqueLocalizacao.SelectSingleNode("EstoqueLocalizacaoFilhos");

				if (xEstoqueLocalizacaoFilhos != null)
				{
					foreach (XmlElement xEstoqueLocalizacaoFilho in xEstoqueLocalizacaoFilhos.ChildNodes)
					{
						GetMovimentacoes(adapter, xDoc, xEstoqueLocalizacaoFilho);
					}
				}
			}
		}

		[Microsoft.SqlServer.Server.SqlTrigger(Name = "GerarEstoqueLocalizacaoHierarquia", Target = "EstoqueLocalizacao", Event = "INSTEAD OF INSERT, UPDATE")]
		public static void GerarEstoqueLocalizacaoHierarquia()
		{
			using (SqlConnection conn = new SqlConnection(@"context connection=true"))
			{
				conn.Open();

				DataTable inserted = new DataTable();
				using (SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM INSERTED", conn))
				{
					adapter.Fill(inserted);
				}

				GerarEstoqueLocalizacaoHierarquia2(conn, inserted.Rows[0]);

				using (SqlCommand command = new SqlCommand())
				{
					command.Connection = conn;

					if (SqlContext.TriggerContext.TriggerAction == TriggerAction.Insert)
					{
						command.CommandText = EstoqueLocalizacao.Insert;
					}
					else if (SqlContext.TriggerContext.TriggerAction == TriggerAction.Update)
					{
						command.CommandText = EstoqueLocalizacao.Update;
					}

					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoRFID", inserted.Rows[0]["EstoqueLocalizacaoRFID"]));
					command.Parameters.Add(new SqlParameter("ativoId", inserted.Rows[0]["AtivoId"]));
					command.Parameters.Add(new SqlParameter("localArmazenagemId", inserted.Rows[0]["LocalArmazenagemId"]));
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoRFIDPai", inserted.Rows[0]["EstoqueLocalizacaoRFIDPai"]));
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoTamanhoCaixa", inserted.Rows[0]["EstoqueLocalizacaoTamanhoCaixa"]));
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoDataValidade", inserted.Rows[0]["EstoqueLocalizacaoDataValidade"]));
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoQuantidade", inserted.Rows[0]["EstoqueLocalizacaoQuantidade"]));
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoHierarquia", inserted.Rows[0]["EstoqueLocalizacaoHierarquia"]));
					command.Parameters.Add(new SqlParameter("estoqueLocalizacaoLote", inserted.Rows[0]["EstoqueLocalizacaoLote"]));

					command.ExecuteNonQuery();
				}

				conn.Close();
			}

		}

		[Microsoft.SqlServer.Server.SqlTrigger(Name = "AtualizaEstoqueLocalizacaoFilhos", Target = "EstoqueLocalizacao", Event = "FOR UPDATE")]
		public static void AtualizaEstoqueLocalizacaoFilhos()
		{
			using (SqlConnection conn = new SqlConnection(@"context connection=true"))
			{
				conn.Open();


				string oldEstoqueLocalizacaoHierarquia = string.Empty;
				string newEstoqueLocalizacaoHierarquia = string.Empty;

				using (SqlCommand command = new SqlCommand(@"
SELECT EstoqueLocalizacaoHierarquia
FROM DELETED", conn))
				{
					oldEstoqueLocalizacaoHierarquia = (string)command.ExecuteScalar();
				}

				using (SqlCommand command = new SqlCommand(@"
SELECT EstoqueLocalizacaoHierarquia
FROM INSERTED", conn))
				{
					newEstoqueLocalizacaoHierarquia = (string)command.ExecuteScalar();
				}

				if (!newEstoqueLocalizacaoHierarquia.Equals(oldEstoqueLocalizacaoHierarquia))
				{
					using (SqlCommand command = new SqlCommand("SELECT * FROM EstoqueLocalizacao WHERE EstoqueLocalizacaoHierarquia LIKE @estoqueLocalizacaoHierarquia + '%' AND EstoqueLocalizacaoHierarquia != @estoqueLocalizacaoHierarquia", conn))
					{
						command.Parameters.Add(new SqlParameter("estoqueLocalizacaoHierarquia", oldEstoqueLocalizacaoHierarquia));

						DataTable estoqueLocalizacao = new DataTable();

						using (SqlDataAdapter adapter = new SqlDataAdapter(command))
						{
							adapter.Fill(estoqueLocalizacao);
						}

						foreach (DataRow row in estoqueLocalizacao.Rows)
						{
							GerarEstoqueLocalizacaoHierarquia2(conn, row);
							command.Parameters.Clear();
							command.CommandText = EstoqueLocalizacao.Update;

							command.Parameters.Add(new SqlParameter("estoqueLocalizacaoRFID", row["EstoqueLocalizacaoRFID"]));
							command.Parameters.Add(new SqlParameter("ativoId", row["AtivoId"]));
							command.Parameters.Add(new SqlParameter("localArmazenagemId", row["LocalArmazenagemId"]));
							command.Parameters.Add(new SqlParameter("estoqueLocalizacaoRFIDPai", row["EstoqueLocalizacaoRFIDPai"]));
							command.Parameters.Add(new SqlParameter("estoqueLocalizacaoTamanhoCaixa", row["EstoqueLocalizacaoTamanhoCaixa"]));
							command.Parameters.Add(new SqlParameter("estoqueLocalizacaoDataValidade", row["EstoqueLocalizacaoDataValidade"]));
							command.Parameters.Add(new SqlParameter("estoqueLocalizacaoQuantidade", row["EstoqueLocalizacaoQuantidade"]));
							command.Parameters.Add(new SqlParameter("estoqueLocalizacaoHierarquia", row["EstoqueLocalizacaoHierarquia"]));
							command.Parameters.Add(new SqlParameter("estoqueLocalizacaoLote", row["EstoqueLocalizacaoLote"]));

							command.ExecuteNonQuery();
						}
					}
				}

				conn.Close();
			}
		}
	}
}
